Skip to content

New sniff to flip ternaries that use compare value on the right side …#2817

Merged
Crabcyborg merged 1 commit into
masterfrom
new_sniff_to_flip_empty_ternaries
Jan 16, 2026
Merged

New sniff to flip ternaries that use compare value on the right side …#2817
Crabcyborg merged 1 commit into
masterfrom
new_sniff_to_flip_empty_ternaries

Conversation

@Crabcyborg

@Crabcyborg Crabcyborg commented Jan 16, 2026

Copy link
Copy Markdown
Contributor

…of the colon in an empty check

This sniff prefers A ? A : B over ! A ? : B : A ternary logic.

Summary by CodeRabbit

  • Refactor

    • Updated conditional logic patterns across form and field components to improve code consistency and maintainability.
  • Chores

    • Extended code quality analysis tooling with a new automated rule to validate and simplify conditional expressions in development workflows.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 16, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The pull request systematically replaces empty() ternary conditionals with truthy checks across multiple form field and helper classes, while introducing a new PHP_CodeSniffer sniff (SimplifyEmptyTernarySniff) to automatically detect and fix such patterns. This refactoring changes from empty($var) ? default : $var to $var ? $var : default, affecting conditional logic in form field handling, XML imports, and admin interface components.

Changes

Cohort / File(s) Summary
Core Logic Ternary Refactoring
classes/controllers/FrmFormsController.php, classes/helpers/FrmFieldsHelper.php, classes/helpers/FrmXMLHelper.php, classes/models/fields/FrmFieldCheckbox.php, classes/models/fields/FrmFieldRadio.php, classes/models/fields/FrmFieldType.php
Replaces empty($var) ? default : $var patterns with truthy checks ($var ? $var : default). Affects form title fallback, error message defaults, parent value assignments, alignment retrieval, and prefix computation. Behavior functionally equivalent for typical cases but treats falsy values (0, '0') more strictly as needing defaults.
Code Quality Tooling
phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/SimplifyEmptyTernarySniff.php
New PHP_CodeSniffer sniff that detects empty-ternary patterns and provides automated fixes. Analyzes T_EMPTY tokens, validates variable matching, and rewrites code to the simplified form with configurable token removal and insertion.
PHPCS Configuration
phpcs-sniffs/Formidable/ruleset.xml
Registers the new Formidable.CodeAnalysis.SimplifyEmptyTernary rule in the Formidable code sniffer ruleset.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Empty checks we simplify,
Ternaries stripped to truth and lie,
A sniff now guards the pattern's gate,
No more empty() truths to state! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: introducing a new sniff to flip ternaries with the compare value on the right side, which aligns with the SimplifyEmptyTernarySniff addition and refactors throughout the codebase.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Crabcyborg
Crabcyborg merged commit fa3667e into master Jan 16, 2026
35 of 36 checks passed
@Crabcyborg
Crabcyborg deleted the new_sniff_to_flip_empty_ternaries branch January 16, 2026 13:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/SimplifyEmptyTernarySniff.php`:
- Around line 60-75: The current check accepts any simple variable inside
empty() (using $varToken, $variableName and $openParen/$closeParen) but the
auto-fix should only run for parameters; change the guard so before returning
you resolve the surrounding function/closure and verify $variableName is
declared in its parameter list (i.e. find the enclosing T_FUNCTION/T_CLOSURE
token and inspect its parameter tokens) and only allow the sniff/fixer to
proceed when the variable matches one of those parameters; otherwise return
without attempting an auto-fix to avoid introducing undefined variable notices.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 542dc94 and ee8f4d0.

📒 Files selected for processing (8)
  • classes/controllers/FrmFormsController.php
  • classes/helpers/FrmFieldsHelper.php
  • classes/helpers/FrmXMLHelper.php
  • classes/models/fields/FrmFieldCheckbox.php
  • classes/models/fields/FrmFieldRadio.php
  • classes/models/fields/FrmFieldType.php
  • phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/SimplifyEmptyTernarySniff.php
  • phpcs-sniffs/Formidable/ruleset.xml
🧰 Additional context used
📓 Path-based instructions (1)
**/*.php

⚙️ CodeRabbit configuration file

**/*.php: - Do not make suggestions when we use x.x for a version placeholder. This is used like "@SInCE x.x" in a PHP doc comment, but also like 'x.x' when functions like _deprecated_function() are used.

  • Treat these placeholders as acceptable in this codebase.

Files:

  • phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/SimplifyEmptyTernarySniff.php
  • classes/models/fields/FrmFieldRadio.php
  • classes/models/fields/FrmFieldType.php
  • classes/helpers/FrmFieldsHelper.php
  • classes/helpers/FrmXMLHelper.php
  • classes/models/fields/FrmFieldCheckbox.php
  • classes/controllers/FrmFormsController.php
🧬 Code graph analysis (4)
phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/SimplifyEmptyTernarySniff.php (1)
phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/FlipNegativeTernarySniff.php (1)
  • getTokensAsString (297-306)
classes/models/fields/FrmFieldRadio.php (1)
classes/controllers/FrmStylesController.php (2)
  • FrmStylesController (6-1489)
  • get_style_val (1283-1291)
classes/helpers/FrmFieldsHelper.php (2)
js/src/admin/admin.js (3)
  • msg (3017-3017)
  • msg (3032-3032)
  • error (9343-9343)
classes/models/FrmInstallerSkin.php (1)
  • error (72-93)
classes/models/fields/FrmFieldCheckbox.php (1)
classes/controllers/FrmStylesController.php (2)
  • FrmStylesController (6-1489)
  • get_style_val (1283-1291)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Cypress
  • GitHub Check: PHP 8 tests in WP 6.9
  • GitHub Check: PHP 7.4 tests in WP 6.9
  • GitHub Check: PHP 8 tests in WP 6.9
  • GitHub Check: PHP 7.4 tests in WP 6.9
  • GitHub Check: Cypress
🔇 Additional comments (10)
phpcs-sniffs/Formidable/ruleset.xml (1)

35-35: Ruleset update looks good.

Line 35 cleanly wires the new sniff into the CodeAnalysis group.

classes/controllers/FrmFormsController.php (1)

2354-2359: Admin bar title update is consistent.

Line 2358 aligns with the new truthy-based ternary pattern without altering expected behavior for form names.

classes/models/fields/FrmFieldCheckbox.php (1)

88-90: Alignment lookup change looks good.

Line 90 matches the new ternary simplification pattern and should behave as expected for form IDs.

classes/helpers/FrmFieldsHelper.php (1)

475-477: Error message fallback update is fine.

Line 476 keeps the fallback logic consistent with the new ternary simplification approach.

classes/models/fields/FrmFieldRadio.php (1)

79-81: Radio alignment lookup change looks good.

Line 81 aligns with the new ternary simplification pattern used elsewhere.

classes/models/fields/FrmFieldType.php (1)

369-371: LGTM — clear truthy fallback.

Line 370 keeps behavior consistent for the $name parameter while aligning with the new ternary style.

classes/helpers/FrmXMLHelper.php (2)

197-198: LGTM — parent fallback preserved.

The truthy check keeps the same fallback behavior for falsy/zero parent IDs.


2387-2389: LGTM — reply-to “from” fallback preserved.

The simplified ternary keeps the intended defaulting to site/admin values when reply-to info is missing.

phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/SimplifyEmptyTernarySniff.php (2)

31-33: LGTM — correct token registration.

Registering T_EMPTY is appropriate for this sniff.


125-127: The project's PHPCS version constraint (squizlabs/php_codesniffer: ^3.10) ensures File::getTokensAsString() is available. This method was introduced in PHPCS 0.0.5 and is stable across all 3.x versions. Three other sniffs in this codebase (SimplifyIfReturnSniff, PreferEscHtmlESniff) already use this API directly without issues, confirming it works reliably in the project's supported environment. While FlipNegativeTernarySniff uses a local helper, this appears to be a stylistic choice rather than a requirement for API compatibility.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +60 to +75
// Get the variable inside empty().
$varToken = $phpcsFile->findNext( T_WHITESPACE, $openParen + 1, $closeParen, true );

if ( false === $varToken || $tokens[ $varToken ]['code'] !== T_VARIABLE ) {
return;
}

$variableName = $tokens[ $varToken ]['content'];

// Check if there's only the variable inside empty() (no array access, etc.).
$nextInParen = $phpcsFile->findNext( T_WHITESPACE, $varToken + 1, $closeParen, true );

if ( false !== $nextInParen ) {
// There's something else inside empty(), skip.
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard against non-parameter variables before auto-fix.

The sniff’s docstring states it’s for function parameters, but Line 67+ accepts any simple variable. Auto-fixing non-parameter locals can introduce “undefined variable” notices. Consider restricting fixes to variables that are declared as parameters in the current function/closure.

♻️ Proposed fix
@@
-		$variableName = $tokens[ $varToken ]['content'];
+		$variableName = $tokens[ $varToken ]['content'];
+
+		// Only simplify when the variable is a parameter of the current function/closure.
+		if ( ! $this->isFunctionParameter( $phpcsFile, $varToken ) ) {
+			return;
+		}
@@
 	}
+
+	private function isFunctionParameter( File $phpcsFile, $varToken ) {
+		$tokens     = $phpcsFile->getTokens();
+		$conditions = $tokens[ $varToken ]['conditions'] ?? array();
+		$functionPtr = null;
+
+		foreach ( array_reverse( $conditions, true ) as $ptr => $type ) {
+			if ( in_array( $type, array( T_FUNCTION, T_CLOSURE, T_FN ), true ) ) {
+				$functionPtr = $ptr;
+				break;
+			}
+		}
+
+		if ( null === $functionPtr || ! isset( $tokens[ $functionPtr ]['parenthesis_opener'] ) ) {
+			return false;
+		}
+
+		$paramStart = $tokens[ $functionPtr ]['parenthesis_opener'] + 1;
+		$paramEnd   = $tokens[ $functionPtr ]['parenthesis_closer'];
+
+		for ( $param = $phpcsFile->findNext( T_VARIABLE, $paramStart, $paramEnd ); false !== $param; $param = $phpcsFile->findNext( T_VARIABLE, $param + 1, $paramEnd ) ) {
+			if ( $tokens[ $param ]['content'] === $tokens[ $varToken ]['content'] ) {
+				return true;
+			}
+		}
+
+		return false;
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Get the variable inside empty().
$varToken = $phpcsFile->findNext( T_WHITESPACE, $openParen + 1, $closeParen, true );
if ( false === $varToken || $tokens[ $varToken ]['code'] !== T_VARIABLE ) {
return;
}
$variableName = $tokens[ $varToken ]['content'];
// Check if there's only the variable inside empty() (no array access, etc.).
$nextInParen = $phpcsFile->findNext( T_WHITESPACE, $varToken + 1, $closeParen, true );
if ( false !== $nextInParen ) {
// There's something else inside empty(), skip.
return;
}
// Get the variable inside empty().
$varToken = $phpcsFile->findNext( T_WHITESPACE, $openParen + 1, $closeParen, true );
if ( false === $varToken || $tokens[ $varToken ]['code'] !== T_VARIABLE ) {
return;
}
$variableName = $tokens[ $varToken ]['content'];
// Only simplify when the variable is a parameter of the current function/closure.
if ( ! $this->isFunctionParameter( $phpcsFile, $varToken ) ) {
return;
}
// Check if there's only the variable inside empty() (no array access, etc.).
$nextInParen = $phpcsFile->findNext( T_WHITESPACE, $varToken + 1, $closeParen, true );
if ( false !== $nextInParen ) {
// There's something else inside empty(), skip.
return;
}
}
private function isFunctionParameter( File $phpcsFile, $varToken ) {
$tokens = $phpcsFile->getTokens();
$conditions = $tokens[ $varToken ]['conditions'] ?? array();
$functionPtr = null;
foreach ( array_reverse( $conditions, true ) as $ptr => $type ) {
if ( in_array( $type, array( T_FUNCTION, T_CLOSURE, T_FN ), true ) ) {
$functionPtr = $ptr;
break;
}
}
if ( null === $functionPtr || ! isset( $tokens[ $functionPtr ]['parenthesis_opener'] ) ) {
return false;
}
$paramStart = $tokens[ $functionPtr ]['parenthesis_opener'] + 1;
$paramEnd = $tokens[ $functionPtr ]['parenthesis_closer'];
for ( $param = $phpcsFile->findNext( T_VARIABLE, $paramStart, $paramEnd ); false !== $param; $param = $phpcsFile->findNext( T_VARIABLE, $param + 1, $paramEnd ) ) {
if ( $tokens[ $param ]['content'] === $tokens[ $varToken ]['content'] ) {
return true;
}
}
return false;
}
🤖 Prompt for AI Agents
In `@phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/SimplifyEmptyTernarySniff.php`
around lines 60 - 75, The current check accepts any simple variable inside
empty() (using $varToken, $variableName and $openParen/$closeParen) but the
auto-fix should only run for parameters; change the guard so before returning
you resolve the surrounding function/closure and verify $variableName is
declared in its parameter list (i.e. find the enclosing T_FUNCTION/T_CLOSURE
token and inspect its parameter tokens) and only allow the sniff/fixer to
proceed when the variable matches one of those parameters; otherwise return
without attempting an auto-fix to avoid introducing undefined variable notices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant